 1.隐式机制之隐式转换
   
   隐式机制主要内容：
       1)、隐式转换
       2)、隐式转换函数
       3)、隐式参数和隐式值
	   
   隐式转换
   隐式转换和隐式参数是Scala中两个非常强大的功能，利用隐式转换和隐式参数，可以提供类库，对类
库的使用者隐匿掉具体的细节。
   
   Scala会根据隐式转换函数的签名，在程序中使用到隐式转换函数接收的参数类型定义的对象时，会自
动将其传入隐式转换函数，转换为另外一种类型的对象并返回，这就是“隐式转换”。
      
	  首先得有一个隐式转换函数
      使用到隐式转换函数接收的参数类型定义的对象
      Scala自动传入隐式转换函数，并完成对象的类型转换
   隐式转换需要使用implicit关键字。
   使用Scala的隐式转换有一定的限制：
       implicit关键字只能用来修饰方法、变量、参数
       隐式转换的函数只在当前范围内才有效。如果隐式转换不在当前范围内定义，那么必须通过
import语句将其导入
   
   Spark源码中有大量的隐式转换和隐式参数，因此必须掌握隐式机制。
 
 2.隐式转换函数
   
   Scala的隐式转换最核心的就是定义隐式转换函数，即implicit conversion function。
   定义的隐式转换函数，只要在编写的程序内引入，就会被Scala自动使用。
   隐式转换函数由Scala自动调用，通常建议将隐式转换函数的名称命名为“one2one”的形式。
   示例1：下面代码中定义了一个隐式函数
   
package lagou.cn.part10

class Num {}

class RichNum(num: Num) {
  def rich(): Unit = {
    println("hello implicit!")
  }
}

object ImplicitDemo {
  //定义一个隐式转换函数，命名要符合one2one的格式
  implicit def num2RichNum(num: Num): RichNum = {
    new RichNum(num)
  }

  def main(args: Array[String]): Unit = {
    val num = new Num
    // num类型的对象没有rich方法，但是Scala编译器会查找当前范围内是否有隐式转换的函数
    //然后将其转换成RichNum类型，这样就可以访问rich方法
    num.rich()
  }
}


   示例2：导入隐式函数
   
package test.implicitdemo

object Int2String {
  implicit def int2String(num: Int):String = num.toString
}

   下面代码中调用了String类型的length方法，Int类型本身没有length方法，但是在可用范围内定义了可
以把Int转换为String的隐式函数int2String，因此函数编译通过并运行出正确的结果。
   
   此示例中隐式函数的定义必须定义在使用之前，否则编译报错。
   
import test.implicitdemo.Int2String._

object ImplicitTest {
  def main(args: Array[String]): Unit = {
    println(20.length)
  }
}

   通过import test.implicitdemo.Int2String._，将Int2StringTest内部的成员导入到相应的作用域内，否
则无法调用隐式函数。
   
   要实现隐式转换，只要在程序可见的范围内定义隐式转换函数即可，Scala会自动使用隐式转换函数。
隐式转换函数与普通函数的语法区别就是，要以implicit开头，而且最好要定义函数返回类型。
   
   隐式转换案例：特殊售票窗口(只接受特殊人群买票,比如学生、老人等)，其他人不能在特殊售票窗
口买票。

class SpecialPerson(var name: String)

class Older(var name: String)

class Student(var name: String)

class Worker(var name: String)
object ImplicitDemoTwo {
  def buySpecialTickWindow(person: SpecialPerson): Unit = {
    if (peron != null) {
	  println(person.name + "购买了一张特殊票！")
    } else {
      println("你不是特殊人群，不能在此买票！")
    }
  }

  //隐式转换函数
  //注意：any参数的类型是Any
  implicit def any2SpecialPerson(any: Any): SpecialPerson = {
    any match {
      case any: Older => new SpecialPerson(any.asInstanceOf[Older].name)
      case any: Student => new SpecialPerson(any.asInstanceOf[Student].name)
      case _ => null
    }
  }

  def main(args: Array[String]): Unit = {
    val stu = new Student("jacky")
    val older = new Older("old man")
    val worker = new Worker("tom")

	ImplicitDemoTwo.buySpecialTickWindow(stu)
    ImplicitDemoTwo.buySpecialTickWindow(older)
    ImplicitDemoTwo.buySpecialTickWindow(worker)
  }
}

 3.隐式参数和隐式值
   
   在函数定义的时候，支持在最后一组参数中使用 implicit ，表明这是一组隐式参数。在调用该函数
的时候，可以不用传递隐式参数，而编译器会自动寻找一个implicit 标记过的合适的值作为参数。
   
   Scala编译器会在两个范围内查找：
     当前作用域内可见的val或var定义隐式变量
     隐式参数类型的伴生对象内隐式值
	 
object Doubly {
  //在print函数中定义一个隐式参数fmt
  def print(num: Double)(implicit fmt: String): Unit = {
    println(fmt format (num))
  }
  def main(args: Array[String]): Unit = {
    //此时调用print函数需要为第二个隐式参数赋值
    print(3.12)("%.1f")

	//定义一个隐式变量
    implicit val printFmt="%.3f"
    //当调用print函数时没有给第二个隐式参数赋值，
    //那么Scala会在当前作用域内寻找可见的val或var定义的隐式变量，一旦找到就会应用
    print(3.12)
  }
}